package top.mengchaob.gitManage.util;

import org.eclipse.jgit.api.*;
import org.eclipse.jgit.api.errors.*;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import top.mengchaob.exception.NotMavenPackageException;
import top.mengchaob.exception.RelationBranchException;
import top.mengchaob.exception.RemoteBranchNotExistException;
import top.mengchaob.util.PropUtil;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @title：
 * @author: mengchaob
 * @date: 2021年05月31日 10:08
 * @description:
 */
public class GitUtil {
    Logger logger = LoggerFactory.getLogger(GitUtil.class);
    private UsernamePasswordCredentialsProvider usernamePasswordCredentialsProvider;
    private Git git = null;
    private Set<String> heads  = new HashSet<String>();
    private Set<String> tags  = new HashSet<String>();
    public static void main(String[] args) throws GitAPIException, RelationBranchException, RemoteBranchNotExistException {
        GitUtil gitUtil = new GitUtil(PropUtil.getV("git.name"),PropUtil.getV("git.password"),PropUtil.getV("git.workSpace"));
//        List branchs = new ArrayList<>();
//        branchs.add("orgin/dev");
//        gitUtil.checkOutBranch("dev");

        gitUtil.gitcloneUrl("http://git.yonyou.com/yygov/F/npcs/npcs-parent-8.30.git","D:\\gittest");
    }

    private GitUtil(){


    }

    public GitUtil(String name, String pass, String fileGitDir){
        File repoGitDir = new File(fileGitDir + "/.git");
        try {
            FileRepository fileRepository = new FileRepository(repoGitDir.getAbsoluteFile());
            git = new Git(fileRepository);
            usernamePasswordCredentialsProvider=
                    new UsernamePasswordCredentialsProvider(name,pass);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 获取远程分支和标签名称
     * @param repoUrl
     * @return
     * @throws GitAPIException
     */
    public List gitRmList(String repoUrl) throws GitAPIException {
        LsRemoteCommand lsRemoteCommand = git.lsRemote();
        Collection<Ref> refs = lsRemoteCommand.setRemote(repoUrl)
                .setCredentialsProvider(usernamePasswordCredentialsProvider)
                .setTags(false)
                .setHeads(false)
                .call();
        List<String> remoteName=new ArrayList<>(refs.size());
        refs.forEach(ref -> {
            String refName = ref.getName();
            if(refName.indexOf("refs/tags")==0){
                String tmp = refName.substring(9,refName.length()-10);
                tags.add(tmp);
                remoteName.add(tmp);
            }
            if(refName.indexOf("refs/heads")==0){
                String tmp = refName.substring(10,refName.length()-10);
                heads.add(tmp);
                remoteName.add(tmp);
            }
        });
        return remoteName;
    }

    public void commitBranch(){

    }

    public List getRemotHeadAndTags(){
        final List list;
        LsRemoteCommand lsRemoteCommand = git.lsRemote();
        try {
            Collection<Ref> crfs = lsRemoteCommand
                    .setCredentialsProvider(usernamePasswordCredentialsProvider)
                    .setRemote(PropUtil.getV("git.url")).setTags(true).setHeads(true).call();
            List<Ref> lrfs = crfs.stream().collect(Collectors.toList());
            list = new ArrayList(lrfs.size());
            lrfs.forEach(ref->{
                Map map = new HashMap();
                map.put("label",ref.getName().split("/")[2]);
                map.put("value",ref.getName().split("/")[2]);
                list.add(map);
            });
            return list;
        } catch (GitAPIException e) {
            e.printStackTrace();
        }
        return new ArrayList(0);
    }

    private boolean isLocalExist(String branchName) throws GitAPIException {
        AtomicBoolean isExist = new AtomicBoolean(false);
        List<Ref>  localRefs = git.branchList().call();
        localRefs.forEach(e->{
            if(e.getName().split("/")[2].equals("local"+branchName)){
                isExist.set(true);
                return;
            }
        });
        return isExist.get();
    }

    /**
     * 获取本地当前分支名称
     * @return
     */
    public String currentBranchName(){
        CheckoutCommand checkoutCommand = git.checkout();
        /**
         * 获取本地当前分支名名称
         */
        String current_name = null;
        try {
            current_name = checkoutCommand.getRepository().getBranch();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return current_name;
    }

    /**
     * 根据远程分支名，拉去本地代码
     * @param branchName
     */
    public void pullBranch(String branchName){

        PullCommand pullCommand = git.pull();
        try {
            String type = this.getTypeByBranchName(branchName);
            String point = type.equals("tags")?"tags/":"heads/";
            pullCommand.setCredentialsProvider(usernamePasswordCredentialsProvider).setRemoteBranchName("refs/"+point+branchName);
            pullCommand.call();
        } catch (GitAPIException e) {
            e.printStackTrace();
        }
    }

    private String getTypeByBranchName(String branchName) throws GitAPIException {
        Collection<Ref>  localRefs = git.lsRemote()
                .setCredentialsProvider(usernamePasswordCredentialsProvider).setHeads(true).setTags(true).call();
        String[] type = {""};
        localRefs.forEach(e->{
            if(e.getName().split("/")[2].equals(branchName)){
                type[0]=e.getName().split("/")[1];
                return;
            }
        });
        return type[0];
    }

    /**
     * 根据带切换得远程分支名切换本地分支
     * @param cheoutBrachName
     */
    public void checkOutBranch(String cheoutBrachName) throws RelationBranchException, RemoteBranchNotExistException {
        try {
            CheckoutCommand checkoutCommand = git.checkout();
            /**
             * 获取本地已经checkOut的分支名称
             */
            LsRemoteCommand lsRemoteCommand = git.lsRemote();
            Map<String, Ref>  refs = lsRemoteCommand
                    .setCredentialsProvider(usernamePasswordCredentialsProvider).callAsMap();
            //head
            String type = this.getTypeByBranchName(cheoutBrachName);
            Ref ref = refs.get("refs/"+type+"/"+cheoutBrachName);
            if(ref!=null){
                //当前分支没有checkout到本地
                if(!isLocalExist(cheoutBrachName)){
                    String point = type.equals("tags")?"":"origin/";
                    try{
                        checkoutCommand
                                .setCreateBranch(true)
                                .setName("local"+cheoutBrachName)
                                //绑定远程分支
                                .setStartPoint(point+cheoutBrachName)
                                .call();
                    }catch (RefAlreadyExistsException rae){
                        rae.printStackTrace();
                    }

                }else{
                        logger.debug("当前远程分支为："+this.currentBranchName());
                        checkoutCommand.setName("local"+cheoutBrachName)
                                .call();
                        logger.debug("切换之后远程分支为："+cheoutBrachName);
                }
            }else{
                throw new RemoteBranchNotExistException("远程分支不存在："+cheoutBrachName);

            }
        } catch (InvalidRefNameException e) {
            e.printStackTrace();
        } catch (CheckoutConflictException e) {
            e.printStackTrace();
        } catch (RefAlreadyExistsException e) {
            e.printStackTrace();
        } catch (RefNotFoundException e) {
            e.printStackTrace();
        } catch (GitAPIException e) {
            e.printStackTrace();
        }
    }

    /**
     * 克隆代码到本地
     * @param repoUrl
     * @param cloneDir
     * @throws GitAPIException
     */
    public void gitcloneUrl(String repoUrl,String cloneDir) throws GitAPIException {
        CloneCommand cloneCommand = Git.cloneRepository();
        Git git = cloneCommand
                .setURI(repoUrl)//要从中克隆的uri
                .setDirectory(new File(cloneDir))//克隆到的目录
                .setCredentialsProvider(usernamePasswordCredentialsProvider)
                .call();
        ListBranchCommand listBranchCommand = git.branchList();
        try {
            String a = listBranchCommand.getRepository().getBranch();
            System.out.println(a);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public List getGitFileByBranch(String branchName) throws NotMavenPackageException {
        File file = new File(PropUtil.getV("maven.localOutDir")+File.separator+branchName);
        if(file.exists() && file.isDirectory()){
            //存在返回列表
            String[] fileName = file.list();
            return Arrays.asList(fileName);
        } else {
          //没有分支文件
            throw new NotMavenPackageException("当前分支尚未经过maven打包！");
        }
    }


}
